﻿namespace AC.ExtendedRenderer.Toolkit
{
    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Drawing;
    using System.Drawing.Drawing2D;
    using System.Runtime.CompilerServices;
    using System.Windows.Forms;
    using System.Windows.Forms.VisualStyles;

    [ToolboxItemFilter("System.Windows.Forms"), Description("Raises an event when the user clicks it."), ToolboxBitmap(typeof(GlassButton)), ToolboxItem(true)]
    public class GlassButton : System.Windows.Forms.Button
    {
        private const int animationLength = 300;
        private Color backColor;
        private IContainer components;
        private int currentFrame;
        private int direction;
        private const int FRAME_ANIMATED = 3;
        private const int FRAME_DISABLED = 0;
        private const int FRAME_NORMAL = 2;
        private const int FRAME_PRESSED = 1;
        private List<Image> frames;
        private const int framesCount = 10;
        private Color glowColor;
        private System.Windows.Forms.Button imageButton;
        private Color innerBorderColor;
        private bool isFocused;
        private bool isFocusedByKey;
        private bool isHovered;
        private bool isKeyDown;
        private bool isMouseDown;
        private Color outerBorderColor;
        private Color shineColor;
        private Timer timer;

        [Description("Event raised when the value of the GlowColor property is changed."), Category("Property Changed")]
        public event System.EventHandler GlowColorChanged;

        [Category("Property Changed"), Description("Event raised when the value of the InnerBorderColor property is changed.")]
        public event System.EventHandler InnerBorderColorChanged;

        [Description("Event raised when the value of the OuterBorderColor property is changed."), Category("Property Changed")]
        public event System.EventHandler OuterBorderColorChanged;

        [Description("Event raised when the value of the ShineColor property is changed."), Category("Property Changed")]
        public event System.EventHandler ShineColorChanged;

        public GlassButton()
        {
            this.InitializeComponent();
            this.timer.Interval = 30;
            base.BackColor = Color.Transparent;
            this.BackColor = Color.Black;
            this.ForeColor = Color.White;
            this.OuterBorderColor = Color.White;
            this.InnerBorderColor = Color.Black;
            this.ShineColor = Color.White;
            this.GlowColor = Color.FromArgb(-7488001);
            base.SetStyle(ControlStyles.OptimizedDoubleBuffer | ControlStyles.AllPaintingInWmPaint | ControlStyles.SupportsTransparentBackColor | ControlStyles.ResizeRedraw | ControlStyles.UserPaint, true);
            base.SetStyle(ControlStyles.Opaque, false);
        }

        public Image CreateBackgroundFrame(bool pressed, bool hovered, bool animating, bool enabled, float glowOpacity)
        {
            Rectangle clientRectangle = base.ClientRectangle;
            if (clientRectangle.Width <= 0)
            {
                clientRectangle.Width = 1;
            }
            if (clientRectangle.Height <= 0)
            {
                clientRectangle.Height = 1;
            }
            Image image = new Bitmap(clientRectangle.Width, clientRectangle.Height);
            using (Graphics graphics = Graphics.FromImage(image))
            {
                graphics.Clear(Color.Transparent);
                DrawButtonBackground(graphics, clientRectangle, pressed, hovered, animating, enabled, this.outerBorderColor, this.backColor, this.glowColor, this.shineColor, this.innerBorderColor, glowOpacity);
            }
            return image;
        }

        private static GraphicsPath CreateBottomRadialPath(Rectangle rectangle)
        {
            GraphicsPath path = new GraphicsPath();
            RectangleF rect = rectangle;
            rect.X -= rect.Width * 0.35f;
            rect.Y -= rect.Height * 0.15f;
            rect.Width *= 1.7f;
            rect.Height *= 2.3f;
            path.AddEllipse(rect);
            path.CloseFigure();
            return path;
        }

        private void CreateFrames()
        {
            this.CreateFrames(false);
        }

        private void CreateFrames(bool withAnimationFrames)
        {
            this.DestroyFrames();
            if (base.IsHandleCreated)
            {
                if (this.frames == null)
                {
                    this.frames = new List<Image>();
                }
                this.frames.Add(this.CreateBackgroundFrame(false, false, false, false, 0f));
                this.frames.Add(this.CreateBackgroundFrame(true, true, false, true, 0f));
                this.frames.Add(this.CreateBackgroundFrame(false, false, false, true, 0f));
                if (withAnimationFrames)
                {
                    for (int i = 0; i < 10; i++)
                    {
                        this.frames.Add(this.CreateBackgroundFrame(false, true, true, true, ((float) i) / 9f));
                    }
                }
            }
        }

        private static GraphicsPath CreateRoundRectangle(Rectangle rectangle, int radius)
        {
            GraphicsPath path = new GraphicsPath();
            int left = rectangle.Left;
            int top = rectangle.Top;
            int width = rectangle.Width;
            int height = rectangle.Height;
            int num5 = radius << 1;
            path.AddArc(left, top, num5, num5, 180f, 90f);
            path.AddLine(left + radius, top, (left + width) - radius, top);
            path.AddArc((left + width) - num5, top, num5, num5, 270f, 90f);
            path.AddLine((int) (left + width), (int) (top + radius), (int) (left + width), (int) ((top + height) - radius));
            path.AddArc((left + width) - num5, (top + height) - num5, num5, num5, 0f, 90f);
            path.AddLine((int) ((left + width) - radius), (int) (top + height), (int) (left + radius), (int) (top + height));
            path.AddArc(left, (top + height) - num5, num5, num5, 90f, 90f);
            path.AddLine(left, (top + height) - radius, left, top + radius);
            path.CloseFigure();
            return path;
        }

        private static GraphicsPath CreateTopRoundRectangle(Rectangle rectangle, int radius)
        {
            GraphicsPath path = new GraphicsPath();
            int left = rectangle.Left;
            int top = rectangle.Top;
            int width = rectangle.Width;
            int height = rectangle.Height;
            int num5 = radius << 1;
            path.AddArc(left, top, num5, num5, 180f, 90f);
            path.AddLine(left + radius, top, (left + width) - radius, top);
            path.AddArc((left + width) - num5, top, num5, num5, 270f, 90f);
            path.AddLine((int) (left + width), (int) (top + radius), (int) (left + width), (int) (top + height));
            path.AddLine(left + width, top + height, left, top + height);
            path.AddLine(left, top + height, left, top + radius);
            path.CloseFigure();
            return path;
        }

        private void DestroyFrames()
        {
            if (this.frames != null)
            {
                while (this.frames.Count > 0)
                {
                    this.frames[this.frames.Count - 1].Dispose();
                    this.frames.RemoveAt(this.frames.Count - 1);
                }
            }
        }

        protected override void Dispose(bool disposing)
        {
            if (disposing)
            {
                if (this.imageButton != null)
                {
                    this.imageButton.Parent.Dispose();
                    this.imageButton.Parent = null;
                    this.imageButton.Dispose();
                    this.imageButton = null;
                }
                this.DestroyFrames();
                if (this.components != null)
                {
                    this.components.Dispose();
                }
            }
            base.Dispose(disposing);
        }

        private static void DrawButtonBackground(Graphics g, Rectangle rectangle, bool pressed, bool hovered, bool animating, bool enabled, Color outerBorderColor, Color backColor, Color glowColor, Color shineColor, Color innerBorderColor, float glowOpacity)
        {
            SmoothingMode smoothingMode = g.SmoothingMode;
            g.SmoothingMode = SmoothingMode.AntiAlias;
            Rectangle rectangle2 = rectangle;
            rectangle2.Width--;
            rectangle2.Height--;
            using (GraphicsPath path = CreateRoundRectangle(rectangle2, 4))
            {
                using (Pen pen = new Pen(outerBorderColor))
                {
                    g.DrawPath(pen, path);
                }
            }
            rectangle2.X++;
            rectangle2.Y++;
            rectangle2.Width -= 2;
            rectangle2.Height -= 2;
            Rectangle rectangle3 = rectangle2;
            rectangle3.Height = rectangle3.Height >> 1;
            using (GraphicsPath path2 = CreateRoundRectangle(rectangle2, 2))
            {
                int alpha = pressed ? 0xcc : 0x7f;
                using (Brush brush = new SolidBrush(Color.FromArgb(alpha, backColor)))
                {
                    g.FillPath(brush, path2);
                }
            }
            if ((hovered || animating) && !pressed)
            {
                using (GraphicsPath path3 = CreateRoundRectangle(rectangle2, 2))
                {
                    g.SetClip(path3, CombineMode.Intersect);
                    using (GraphicsPath path4 = CreateBottomRadialPath(rectangle2))
                    {
                        using (PathGradientBrush brush2 = new PathGradientBrush(path4))
                        {
                            int num2 = (int) ((178f * glowOpacity) + 0.5f);
                            RectangleF bounds = path4.GetBounds();
                            brush2.CenterPoint = new PointF((bounds.Left + bounds.Right) / 2f, (bounds.Top + bounds.Bottom) / 2f);
                            brush2.CenterColor = Color.FromArgb(num2, glowColor);
                            brush2.SurroundColors = new Color[] { Color.FromArgb(0, glowColor) };
                            g.FillPath(brush2, path4);
                        }
                    }
                    g.ResetClip();
                }
            }
            if ((rectangle3.Width > 0) && (rectangle3.Height > 0))
            {
                rectangle3.Height++;
                using (GraphicsPath path5 = CreateTopRoundRectangle(rectangle3, 2))
                {
                    rectangle3.Height++;
                    int num3 = 0x99;
                    if (pressed | !enabled)
                    {
                        num3 = (int) ((0.4f * num3) + 0.5f);
                    }
                    using (LinearGradientBrush brush3 = new LinearGradientBrush(rectangle3, Color.FromArgb(num3, shineColor), Color.FromArgb(num3 / 3, shineColor), LinearGradientMode.Vertical))
                    {
                        g.FillPath(brush3, path5);
                    }
                }
                rectangle3.Height -= 2;
            }
            using (GraphicsPath path6 = CreateRoundRectangle(rectangle2, 3))
            {
                using (Pen pen2 = new Pen(innerBorderColor))
                {
                    g.DrawPath(pen2, path6);
                }
            }
            g.SmoothingMode = smoothingMode;
        }

        private void DrawButtonBackgroundFromBuffer(Graphics graphics)
        {
            int num;
            if (!base.Enabled)
            {
                num = 0;
            }
            else if (this.isPressed)
            {
                num = 1;
            }
            else if (!this.isAnimating && (this.currentFrame == 0))
            {
                num = 2;
            }
            else
            {
                if (!this.HasAnimationFrames)
                {
                    this.CreateFrames(true);
                }
                num = 3 + this.currentFrame;
            }
            if (this.frames == null)
            {
                this.CreateFrames();
            }
            graphics.DrawImage(this.frames[num], Point.Empty);
        }

        private void DrawButtonForeground(Graphics g)
        {
            if (this.Focused && this.ShowFocusCues)
            {
                Rectangle clientRectangle = base.ClientRectangle;
                clientRectangle.Inflate(-4, -4);
                ControlPaint.DrawFocusRectangle(g, clientRectangle);
            }
        }

        private void DrawForegroundFromButton(PaintEventArgs pevent)
        {
            if (this.imageButton == null)
            {
                this.imageButton = new System.Windows.Forms.Button();
                this.imageButton.Parent = new TransparentControl();
                this.imageButton.BackColor = Color.Transparent;
                this.imageButton.FlatAppearance.BorderSize = 0;
                this.imageButton.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
            }
            this.imageButton.AutoEllipsis = base.AutoEllipsis;
            if (base.Enabled)
            {
                this.imageButton.ForeColor = this.ForeColor;
            }
            else
            {
                this.imageButton.ForeColor = Color.FromArgb(((3 * this.ForeColor.R) + this.backColor.R) >> 2, ((3 * this.ForeColor.G) + this.backColor.G) >> 2, ((3 * this.ForeColor.B) + this.backColor.B) >> 2);
            }
            this.imageButton.Font = this.Font;
            this.imageButton.RightToLeft = this.RightToLeft;
            this.imageButton.Image = base.Image;
            this.imageButton.ImageAlign = base.ImageAlign;
            this.imageButton.ImageIndex = base.ImageIndex;
            this.imageButton.ImageKey = base.ImageKey;
            this.imageButton.ImageList = base.ImageList;
            this.imageButton.Padding = base.Padding;
            this.imageButton.Size = base.Size;
            this.imageButton.Text = this.Text;
            this.imageButton.TextAlign = this.TextAlign;
            this.imageButton.TextImageRelation = base.TextImageRelation;
            this.imageButton.UseCompatibleTextRendering = base.UseCompatibleTextRendering;
            this.imageButton.UseMnemonic = base.UseMnemonic;
            base.InvokePaint(this.imageButton, pevent);
        }

        private void FadeIn()
        {
            this.direction = 1;
            this.timer.Enabled = true;
        }

        private void FadeOut()
        {
            this.direction = -1;
            this.timer.Enabled = true;
        }

        private void InitializeComponent()
        {
            this.components = new Container();
            this.timer = new Timer(this.components);
            base.SuspendLayout();
            this.timer.Tick += new System.EventHandler(this.timer_Tick);
            base.ResumeLayout(false);
        }

        protected override void OnClick(EventArgs e)
        {
            this.isKeyDown = this.isMouseDown = false;
            base.OnClick(e);
        }

        protected override void OnEnter(EventArgs e)
        {
            this.isFocused = this.isFocusedByKey = true;
            base.OnEnter(e);
        }

        protected virtual void OnGlowColorChanged(EventArgs e)
        {
            if (this.GlowColorChanged != null)
            {
                this.InnerBorderColorChanged(this, e);
            }
        }

        protected virtual void OnInnerBorderColorChanged(EventArgs e)
        {
            if (this.InnerBorderColorChanged != null)
            {
                this.InnerBorderColorChanged(this, e);
            }
        }

        protected override void OnKeyDown(KeyEventArgs kevent)
        {
            if (kevent.KeyCode == Keys.Space)
            {
                this.isKeyDown = true;
                base.Invalidate();
            }
            base.OnKeyDown(kevent);
        }

        protected override void OnKeyUp(KeyEventArgs kevent)
        {
            if (this.isKeyDown && (kevent.KeyCode == Keys.Space))
            {
                this.isKeyDown = false;
                base.Invalidate();
            }
            base.OnKeyUp(kevent);
        }

        protected override void OnLeave(EventArgs e)
        {
            base.OnLeave(e);
            this.isFocused = this.isFocusedByKey = this.isKeyDown = this.isMouseDown = false;
            base.Invalidate();
        }

        protected override void OnMouseDown(MouseEventArgs e)
        {
            if (!this.isMouseDown && (e.Button == MouseButtons.Left))
            {
                this.isMouseDown = true;
                this.isFocusedByKey = false;
                base.Invalidate();
            }
            base.OnMouseDown(e);
        }

        protected override void OnMouseEnter(EventArgs e)
        {
            this.isHovered = true;
            this.FadeIn();
            base.Invalidate();
            base.OnMouseEnter(e);
        }

        protected override void OnMouseLeave(EventArgs e)
        {
            this.isHovered = false;
            this.FadeOut();
            base.Invalidate();
            base.OnMouseLeave(e);
        }

        protected override void OnMouseMove(MouseEventArgs mevent)
        {
            base.OnMouseMove(mevent);
            if (mevent.Button != MouseButtons.None)
            {
                if (!base.ClientRectangle.Contains(mevent.X, mevent.Y))
                {
                    if (this.isHovered)
                    {
                        this.isHovered = false;
                        base.Invalidate();
                    }
                }
                else if (!this.isHovered)
                {
                    this.isHovered = true;
                    base.Invalidate();
                }
            }
        }

        protected override void OnMouseUp(MouseEventArgs e)
        {
            if (this.isMouseDown)
            {
                this.isMouseDown = false;
                base.Invalidate();
            }
            base.OnMouseUp(e);
        }

        protected virtual void OnOuterBorderColorChanged(EventArgs e)
        {
            if (this.OuterBorderColorChanged != null)
            {
                this.OuterBorderColorChanged(this, e);
            }
        }

        protected override void OnPaint(PaintEventArgs pevent)
        {
            this.DrawButtonBackgroundFromBuffer(pevent.Graphics);
            this.DrawForegroundFromButton(pevent);
            this.DrawButtonForeground(pevent.Graphics);
        }

        protected virtual void OnShineColorChanged(EventArgs e)
        {
            if (this.ShineColorChanged != null)
            {
                this.ShineColorChanged(this, e);
            }
        }

        protected override void OnSizeChanged(EventArgs e)
        {
            this.CreateFrames();
            base.OnSizeChanged(e);
        }

        private void timer_Tick(object sender, EventArgs e)
        {
            if (this.timer.Enabled)
            {
                this.Refresh();
                this.currentFrame += this.direction;
                if (this.currentFrame == -1)
                {
                    this.currentFrame = 0;
                    this.timer.Enabled = false;
                    this.direction = 0;
                }
                else if (this.currentFrame == 10)
                {
                    this.currentFrame = 9;
                    this.timer.Enabled = false;
                    this.direction = 0;
                }
            }
        }

        [DefaultValue(typeof(Color), "Black")]
        public virtual Color BackColor
        {
            get
            {
                return this.backColor;
            }
            set
            {
                if (!this.backColor.Equals(value))
                {
                    this.backColor = value;
                    this.UseVisualStyleBackColor = false;
                    this.CreateFrames();
                    this.OnBackColorChanged(EventArgs.Empty);
                }
            }
        }

        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
        public FlatButtonAppearance FlatAppearance
        {
            get
            {
                return base.FlatAppearance;
            }
        }

        [Browsable(false), EditorBrowsable(EditorBrowsableState.Never), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public System.Windows.Forms.FlatStyle FlatStyle
        {
            get
            {
                return base.FlatStyle;
            }
            set
            {
                base.FlatStyle = value;
            }
        }

        [DefaultValue(typeof(Color), "White")]
        public virtual Color ForeColor
        {
            get
            {
                return base.ForeColor;
            }
            set
            {
                base.ForeColor = value;
            }
        }

        [Description("The glow color of the control."), Category("Appearance"), DefaultValue(typeof(Color), "255,141,189,255")]
        public virtual Color GlowColor
        {
            get
            {
                return this.glowColor;
            }
            set
            {
                if (this.glowColor != value)
                {
                    this.glowColor = value;
                    this.CreateFrames();
                    if (base.IsHandleCreated)
                    {
                        base.Invalidate();
                    }
                    this.OnGlowColorChanged(EventArgs.Empty);
                }
            }
        }

        private bool HasAnimationFrames
        {
            get
            {
                return ((this.frames != null) && (this.frames.Count > 3));
            }
        }

        [DefaultValue(typeof(Color), "Black"), Description("The inner border color of the control."), Category("Appearance")]
        public virtual Color InnerBorderColor
        {
            get
            {
                return this.innerBorderColor;
            }
            set
            {
                if (this.innerBorderColor != value)
                {
                    this.innerBorderColor = value;
                    this.CreateFrames();
                    if (base.IsHandleCreated)
                    {
                        base.Invalidate();
                    }
                    this.OnInnerBorderColorChanged(EventArgs.Empty);
                }
            }
        }

        private bool isAnimating
        {
            get
            {
                return (this.direction != 0);
            }
        }

        private bool isPressed
        {
            get
            {
                return (this.isKeyDown || (this.isMouseDown && this.isHovered));
            }
        }

        [Description("The outer border color of the control."), DefaultValue(typeof(Color), "White"), Category("Appearance")]
        public virtual Color OuterBorderColor
        {
            get
            {
                return this.outerBorderColor;
            }
            set
            {
                if (this.outerBorderColor != value)
                {
                    this.outerBorderColor = value;
                    this.CreateFrames();
                    if (base.IsHandleCreated)
                    {
                        base.Invalidate();
                    }
                    this.OnOuterBorderColorChanged(EventArgs.Empty);
                }
            }
        }

        [DefaultValue(typeof(Color), "White"), Description("The shine color of the control."), Category("Appearance")]
        public virtual Color ShineColor
        {
            get
            {
                return this.shineColor;
            }
            set
            {
                if (this.shineColor != value)
                {
                    this.shineColor = value;
                    this.CreateFrames();
                    if (base.IsHandleCreated)
                    {
                        base.Invalidate();
                    }
                    this.OnShineColorChanged(EventArgs.Empty);
                }
            }
        }

        [Browsable(false)]
        public PushButtonState State
        {
            get
            {
                if (!base.Enabled)
                {
                    return PushButtonState.Disabled;
                }
                if (this.isPressed)
                {
                    return PushButtonState.Pressed;
                }
                if (this.isHovered)
                {
                    return PushButtonState.Hot;
                }
                if (!this.isFocused && !base.IsDefault)
                {
                    return PushButtonState.Normal;
                }
                return PushButtonState.Default;
            }
        }

        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
        public bool UseVisualStyleBackColor
        {
            get
            {
                return base.UseVisualStyleBackColor;
            }
            set
            {
                base.UseVisualStyleBackColor = value;
            }
        }

        private class TransparentControl : Control
        {
            protected override void OnPaint(PaintEventArgs e)
            {
            }

            protected override void OnPaintBackground(PaintEventArgs pevent)
            {
            }
        }
    }
}

